#include <iostream>
#include <memory>
#include <string>

class Man
{
public:
    std::string name;
    int age;
    Man(){}
    Man(std::string name, int age):name(name),age(age)
    {std::cout<<"man has been created\n";}
    void printman()
    {
        std::cout<<"name: "<<name<<" age:"<<age<<std::endl;
    }
};

int main(int, char**){
    std::cout<<"\nHello, from smart_ptr!\n";
    // 尽量使用智能指针而不是裸指针，尽量不要用new来生成裸指针！！！
    // ************************unique_ptr***********************
    // unique_ptr智能指针对于其指向的资源是独享的，不允许其他指针指向
    // 使用reset方法创建智能指针 unique_ptr
    std::unique_ptr<Man> p;
    p.reset(new Man("小芳",15));
    p->name = "小兰";
    p->age = 10;
    p->printman();
    // 使用make_unique()函数创建 智能指针
    std::unique_ptr<Man> upm1(new Man("小哀",10));  // 这种也能用
    upm1->printman();
    auto upm2(std::make_unique<Man>("园子",17));    //  推荐这种方法-----------
    upm2->printman();
    // std::cout<<"\n"<<upm2->name<<"\n";   //就和普通new出来的指针一样用
    std::unique_ptr<Man> upm3(std::make_unique<Man>("小欢",18));    // 这个冗杂
    upm3->printman();
    

    // ************************shared_ptr***********************
    // 共享智能指针的用处就是多个指针指向同一个内存块，但是引用量为0后自动清理内存，实现了内存管理的智能化
    std::shared_ptr<Man> spw1(std::make_shared<Man>("柯南",12));
    spw1->printman();
    auto spw2(std::make_shared<Man>("新一",24));    // 推荐这一种-----------------(引发一次内存分配，Man型别对象和控制块分配在一起)
    spw2->printman();
    // 这种用到了new
    std::shared_ptr<Man> spw3(new Man("雪莉",25)); // 用裸指针来构造共享智能指针，虽然用了new，但至少不会造成内存泄漏。
                                            // 另外这种操作会引发两侧内存分配。
                                            // 这种new决不能写在外面，如果用同一个裸指针构造了两个shared智能指针，那么可能会析构两次类
    spw3->printman();
    // 接下来演示如何共享
    auto spw4(spw3);    // 创建一个指向雪莉的第二个共享智能指针
    spw4->printman();
    spw4->name = "雪莉缩小版";  // 通过spw4改变其指涉对象的name
    spw3->printman();         // 通过spw3查看 name: 雪莉缩小版 age:25
                            // 由此得到spw3和spw4指涉的对象是同一个

    // 对于unique_ptr 和 shared_ptr 初始化的时候都可以为其传入自定义的析构函数
    // 千万不要这么用：
    Man* ptr = new Man("错误",-1);
    std::shared_ptr<Man> spm00(ptr);    // 这就创建了两个shared共享指针的控制块，可能引发两次析构
    std::shared_ptr<Man> spm01(ptr);    // free(): double free detected in tcache 2，程序结束时报错，两次析构
    spm00->printman();                  // 这里可以正常执行
    // delete spm00;    不能这么删除，智能指针会在退出其生命周期时自动析构，控制块中的引用数量减一
}
